Add seperate project file for misc. GPS data parser functions.
authoroliskoli <oliskoli>
Mon, 20 Aug 2007 21:43:39 +0000 (21:43 +0000)
committeroliskoli <oliskoli>
Mon, 20 Aug 2007 21:43:39 +0000 (21:43 +0000)
parse.c [new file with mode: 0644]

diff --git a/parse.c b/parse.c
new file mode 100644 (file)
index 0000000..ce107a1
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,235 @@
+/*
+
+    Misc GPS (text to data) parsers.
+
+    Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "defs.h"
+#include "jeeps/gpsmath.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+
+/*
+ * parse_distance:
+ *
+ *  str:     input string, i.e. "128.2 km" or "22mi"
+ *  val:     pointer to resulting value
+ *  scale:   scaling parameter for unit-less values
+ *  module:  calling module, i.e. "garmin_txt"
+ */
+
+int
+parse_distance(const char *str, double *val, double scale, const char *module)
+{
+       char *unit;
+       
+       if ((str == NULL) || (*str == '\0')) return 0;
+       
+       *val = strtod(str, &unit);
+       if (unit == NULL)
+               fatal("%s: Unconvertable numeric value (%s)!\n", module, str);
+
+       if (fabs(*val) + 1 >= 1.0e25) {
+               return 0; /* not only Garmin uses this as 'unknown value' */
+       }
+       
+       while (isspace(*unit)) unit++;
+       
+       if (*unit == '\0') {
+               *val *= scale;
+               return 1;
+       }
+       
+       if (case_ignore_strcmp(unit, "m") == 0) /* do nothing, that's our standard */;
+       else if (case_ignore_strcmp(unit, "ft") == 0) *val = FEET_TO_METERS(*val);
+       else if (case_ignore_strcmp(unit, "feet") == 0) *val = FEET_TO_METERS(*val);
+       else if (case_ignore_strcmp(unit, "km") == 0) *val *= 1000.0;
+       else if (case_ignore_strcmp(unit, "nm") == 0) *val = NMILES_TO_METERS(*val);
+       else if (case_ignore_strcmp(unit, "mi") == 0) *val = MILES_TO_METERS(*val);
+       else if (case_ignore_strcmp(unit, "fa") == 0) *val = FATHOMS_TO_METERS(*val);
+       else
+               fatal("%s: Unsupported distance unit in item '%s'!\n", module, str);
+       return 2;
+}
+
+/*
+ * parse_speed:
+ *
+ *  str:     input string, i.e. "22.3 km/h" or "40mph"
+ *  val:     pointer to resulting value
+ *  scale:   scaling parameter for unit-less values
+ *  module:  calling module, i.e. "garmin_txt"
+ */
+int
+parse_speed(const char *str, double *val, const double scale, const char *module)
+{
+       char *unit;
+       
+       if ((str == NULL) || (*str == '\0')) return 0;
+       
+       *val = strtod(str, &unit);
+       if (unit == NULL)
+               fatal("%s: Unconvertable numeric value (%s)!\n", module, str);
+       
+       while (isspace(*unit)) unit++;
+       
+       if (*unit == '\0') {
+               *val *= scale;
+               return 1;
+       }
+       
+       if (case_ignore_strcmp(unit, "m/s") == 0) ;
+       else if (case_ignore_strcmp(unit, "mps") == 0) ;
+       else if (case_ignore_strcmp(unit, "kph") == 0) *val = KPH_TO_MPS(*val);
+       else if (case_ignore_strcmp(unit, "km/h") == 0) *val = KPH_TO_MPS(*val);
+       else if (case_ignore_strcmp(unit, "kt") == 0) *val = KNOTS_TO_MPS(*val);
+       else if (case_ignore_strcmp(unit, "knot") == 0) *val = KNOTS_TO_MPS(*val);
+       else if (case_ignore_strcmp(unit, "mph") == 0) *val = MPH_TO_MPS(*val);
+       else if (case_ignore_strcmp(unit, "mi/h") == 0) *val = MPH_TO_MPS(*val);
+       else
+               fatal("%s: Unsupported speed unit '%s' in item '%s'!\n", module, unit, str);
+
+       return 2;
+}
+
+/* 
+ * Convert string 'str' into geodetic latitide & longitude values. The format
+ * will be interpreted depending on 'grid' parameter.
+ *
+ * return value: number of characters efective parsed
+ */
+
+int
+parse_coordinates(const char *str, int datum, const grid_type grid, 
+       double *latitude, double *longitude, const char *module)
+{
+       double lat, lon;
+       unsigned char lathemi, lonhemi;
+       int deg_lat, deg_lon, min_lat, min_lon;
+       char map[3];
+       int utmz;
+       double utme, utmn;
+       char utmc;
+       int valid, result, ct;
+       double lx, ly;
+       const char *format;
+       
+       valid = 1;
+       
+       switch(grid) {
+
+               case grid_lat_lon_ddd:
+                       format = "%c%lf %c%lf%n";
+                       ct = sscanf(str, format,
+                               &lathemi, &lat, &lonhemi, &lon, &result);
+                       valid = (ct == 4);
+                       break;
+
+               case grid_lat_lon_dmm:
+                       format = "%c%d %lf %c%d %lf%n";
+                       ct = sscanf(str, format,
+                               &lathemi, &deg_lat, &lat, &lonhemi, &deg_lon, &lon, &result);
+                       valid = (ct == 6);
+                       if (valid) {
+                               lat = (double)deg_lat + (lat / (double)60);
+                               lon = (double)deg_lon + (lon / (double)60);
+                       }
+                       break;
+               
+               case grid_lat_lon_dms:
+                       format = "%c%d %d %lf %c%d %d %lf%n";
+                       ct = sscanf(str, format,
+                               &lathemi, &deg_lat, &min_lat, &lat, &lonhemi, &deg_lon, &min_lon, &lon,
+                               &result);
+                       valid = (ct == 8);
+                       if (valid) {
+                               lat = (double)deg_lat + ((double)min_lat / (double)60) + (lat / (double)3600.0);
+                               lon = (double)deg_lon + ((double)min_lon / (double)60) + (lon / (double)3600.0);
+                       }
+                       break;
+               
+               case grid_bng:
+                       datum = DATUM_WGS84;    /* fix */
+                       format = "%2s %lf %lf%n";
+                       ct = sscanf(str, format,
+                               map, &lx, &ly,
+                               &result);
+                       valid = (ct == 3);
+                       if (valid) {
+                               if (! GPS_Math_UKOSMap_To_WGS84_M(map, lx, ly, &lat, &lon))
+                                       fatal("%s: Unable to convert BNG coordinates (%s)!\n",
+                                               module, str);
+                       }
+                       lathemi = lonhemi = '\0';
+                       break;
+                       
+               case grid_utm:
+                       format = "%d %c %lf %lf%n";
+                       ct = sscanf(str, format,
+                               &utmz, &utmc, &utme, &utmn,
+                               &result);
+                       valid = (ct == 4);
+                       if (valid) {
+                               if (! GPS_Math_UTM_EN_To_Known_Datum(&lat, &lon, utme, utmn, utmz, utmc, datum))
+                                       fatal("%s: Unable to convert UTM coordinates (%s)!\n",
+                                               module, str);
+                       }
+                       lathemi = lonhemi = '\0';
+                       break;
+                       
+               case grid_swiss: {
+                       double east, north;
+               
+                       datum = DATUM_WGS84;    /* fix */
+                       format = "%lf %lf%n";
+                       ct = sscanf(str, format,
+                               &east, &north, &result);
+                       valid = (ct == 2);
+                       GPS_Math_CH1903_NGEN_To_WGS84(east, north, &lat, &lon);
+                       break;
+               }
+               default:
+                       /* this should never happen in a release version */
+                       fatal("%s/util: Unknown grid in parse_coordinates (%d)!\n",
+                               module, (int)grid);
+       }
+       
+       if (! valid) {
+               warning("%s: sscanf error using format \"%s\"!\n", module, format);
+               warning("%s: parsing has stopped at parameter number %d.\n", module, ct);
+               fatal("%s: could not convert coordinates \"%s\"!\n", module, str);
+       }
+       
+       if (lathemi == 'S') lat = -lat;
+       if (lonhemi == 'W') lon = -lon;
+
+       if (datum != DATUM_WGS84) {
+               double alt;
+               GPS_Math_Known_Datum_To_WGS84_M(lat, lon, (double) 0.0,
+                       &lat, &lon, &alt, datum);
+       }
+
+       if (latitude) *latitude = lat;
+       if (longitude) *longitude = lon;
+               
+       return result;
+}